iT邦幫忙

2024 iThome 鐵人賽

DAY 4
0
Software Development

輕鬆學習設計模式Design Pattern系列 第 4

Day 4 裝飾者模式 Decorator Pattern

  • 分享至 

  • xImage
  •  

在日常生活中,我們經常會去咖啡店買咖啡,但如果想要來點變化,像是加一點牛奶或糖,就可以讓平凡的咖啡多一點風味。同樣地,在程式設計中,我們有時也需要在不改變原有功能的前提下,為某些物件「加點料」。這就是裝飾者模式 Decorator Pattern 所要解決的問題。

什麼是裝飾者模式?

裝飾者模式是一種結構型設計模式,它允許你動態地為物件添加功能,而不需要修改其原有的程式碼。換句話說,裝飾者模式讓你可以根據不同的需求,隨時為一個物件「增添佐料」,就像你為咖啡加牛奶或糖一樣,都會改變咖啡的口感和價格,但我們並沒有改變咖啡本身。

裝飾者模式在咖啡店的應用

讓我們用一個簡單的例子來說明。假設我們有一個基本的咖啡類別 Coffee,它代表一杯不加任何配料的黑咖啡。你可以根據需求選擇加入牛奶、糖或其他配料。使用裝飾者模式,我們可以輕鬆地計算出各種組合的價格,而不需要為每種可能的組合建立新的類別。

首先,我們定義一個 Coffee 類別,並為它計算基本價錢的功能:

class Coffee {
public:
    virtual std::string getDescription() const {
        return "黑咖啡";
    }
    virtual int cost() const {
        return 50;
    }
    virtual ~Coffee() = default;
};

假設你想在咖啡中加牛奶,我們可以建立一個裝飾者類別 MilkDecorator,這個類別將會裝飾(也就是包裝)Coffee 類別,並在其基礎上增加牛奶的功能:

class MilkDecorator : public Coffee {
private:
    std::unique_ptr<Coffee> coffee;

public:
    MilkDecorator(std::unique_ptr<Coffee> c) : coffee(std::move(c)) {}

    std::string getDescription() const override {
        return coffee->getDescription() + "+牛奶";
    }

    int cost() const override {
        return coffee->cost() + 15;
    }
};

如果你想再加點糖,可以再建立一個 SugarDecorator 類別:

class SugarDecorator : public Coffee {
private:
    std::unique_ptr<Coffee> coffee;

public:
    SugarDecorator(std::unique_ptr<Coffee> c) : coffee(std::move(c)) {}

    std::string getDescription() const override {
        return coffee->getDescription() + "+糖";
    }

    int cost() const override {
        return coffee->cost() + 5;
    }
};

最後我們就可以根據自己的需求自由組合這些裝飾者:

int main() {
    std::unique_ptr<Coffee> coffee = std::make_unique<Coffee>();
    std::cout << coffee->getDescription() << "價格:"
              << coffee->cost() << "元\n";
    coffee = std::make_unique<MilkDecorator>(std::move(coffee));
    std::cout << coffee->getDescription() << "價格:"
              << coffee->cost() << "元\n";
    coffee = std::make_unique<SugarDecorator>(std::move(coffee));
    std::cout << coffee->getDescription() << "價格:"
              << coffee->cost() << "元\n";

    return 0;
}

執行上述程式碼,我們會得到以下輸出:

黑咖啡價格:50元
黑咖啡+牛奶價格:65元
黑咖啡+牛奶+糖價格:70元

在這個範例中,我們從一杯基本的黑咖啡開始,然後動態地添加牛奶和糖,最終計算出一杯加了牛奶和糖的咖啡價格。每次添加新配料時,我們不需要修改現有的咖啡類別,只需透過裝飾者來實現功能的擴展。這樣的設計讓我們可以靈活地擴展功能,也讓程式碼更加易於維護。

裝飾者模式的優點

裝飾者模式的最大優點就是靈活性,你可以任意組合裝飾者成各種不同的組合。當你面對需要不斷添加新功能的情況時,使用裝飾者模式可以避免類別數量的膨脹,讓程式碼更易於維護和擴展。同時它也保持了開放封閉原則,也就是添加新的裝飾者不需要修改原始類別,也符合單一職責原則,即每個裝飾者只負責一項特定的功能增強。

總結

裝飾者模式就像是在咖啡裡添加牛奶和糖,讓原本簡單的東西變得更加豐富多樣。在程式設計中,它能幫助我們以一種靈活的方式,擴展物件的功能,同時保持程式碼的清晰與可維護性。下次當你面臨需要擴展物件功能的需求時,考慮一下裝飾者模式,它或許就是你需要的解決方案!

更多C++語言相關的文章,歡迎追蹤我的部落格
https://shengyu7697.github.io/cpp-decorator-pattern/


上一篇
Day 3 觀察者模式 Observer Pattern
下一篇
Day 5 樣板方法模式 Template Method Pattern
系列文
輕鬆學習設計模式Design Pattern30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言